/** @file Command.cc
 * Implementation of class Command.
 */
#include <iostream>
#include <cstdlib>		// for: getenv()
#include <unistd.h>		// for: getcwd()

  #include <stdio.h>
#include <limits.h>		// for: PATH_MAX
#include <fcntl.h>		// for: O_RDONLY, O_CREAT, O_WRONLY, O_APPEND
#include <sstream>
#include <istream>

#include "asserts.h"
#include "unix_error.h"
#include "Command.h"


// Iff PATH_MAX is not defined in limits.h
#ifndef	PATH_MAX
# define	PATH_MAX (4096)	/* i.e. virtual pagesize */
#endif


Command::Command()
	: append(false)
{
}


void	Command::addWord(string& word)
{
	words.push_back(word);
}


void	Command::setInput(std::string& the_input)
{
	require(input.empty());		// catch multiple inputs
	input = the_input;
}

void	Command::setOutput(std::string& the_output)
{
	require(output.empty());	// catch multiple outputs
	output = the_output;
	append = false;
}

void	Command::setAppend(std::string& the_output)
{
	require(output.empty());	// catch multiple outputs
	output = the_output;
	append = true;
}

// A true "no-nothing" command?
bool	Command::isEmpty() const
{
	return input.empty() && output.empty() && words.empty();
}


// ===========================================================


// Execute a command
void	Command::execute()
{
	//cerr << "Command:execute\n";//DEBUG

	// TODO:	Handle I/O redirections.
	// TODO:	Convert the words vector<string> to: array of (char*) as expected by 'execv'.
	//			NOTE: Make sure the last element of that array will be a 0 pointer!
	// TODO:	Determine the full name of the program to be executed.
	// 			If the name begins with '/' it already is an full name.
	// 			If the name begins with "./" it is expressed relative to the
	// 			current directory.
	// 			Otherwise it is to be searched for using the PATH
	// 			environment variable.
	// TODO:	Execute the program passing the arguments array.
	// Also see: close(2), open(2), getcwd(3), getenv(3), access(2), execv(2), exit(2)

#if 0	/* DEBUG code: Set to 0 to turn off the next block of code */
	cerr <<"Command::execute ";
	// Show the I/O redirections first
	if (!input.empty())
		cerr << " <"<< input;
	if (!output.empty()) {
		if (append)
			cerr << " >>"<< output;
		else
			cerr << " >"<< output;
	}
	// Then show the command & parameters to execute
	if (words.empty())
		cerr << "\t(DO_NOTHING)";
	else
		cerr << "\t";
	for (vector<string>::iterator  i = words.begin() ; i != words.end() ; ++i)
		cerr << " " << *i;

	cerr << endl;
#endif	/* end DEBUG code */
	
	// TODO 



	if(this->hasInput())
	{
		 char *input =  (char*)this->input.c_str();
		 int fd = open(input, O_RDONLY);
		 if (fd < 0)
			 throw unix_error("could not open file");
		 if (dup2(fd, 0) != 0)  // Testing that the file descriptor is 0
			 throw unix_error("could not dup2");
		 close(fd);
	}

	if(this->hasOutput())
	{
		 char *output =  (char*)this->output.c_str();
		 int fd;
		 if(this->append)
		 {
			 fd = open(output, O_WRONLY | O_APPEND);
		 }
		 else{
		 fd = open(output, O_WRONLY | O_CREAT);
		 }

		 if (fd < 0)
			 throw unix_error("could not open file");
		 dup2(fd, 1);
		 close(fd);
	}



	// commando uitvoerenren
	char * argv[words.size()];
	for (unsigned int j = 0; j < words.size(); j++) {
		argv[j] = const_cast<char*>(words.at(j).c_str());
	}

	argv[words.size()] = NULL;


	//TODO check of begint met '/' of './'

	//test paths
	vector<string> paths = getPaths();
	for(int i=0; i < paths.size(); i++){
		string command;
		command.append(paths[i]);
		command.append("/");
		command.append(argv[0]);
		//paths[i] + '/' + argv[0];

		char * commandChar = (char*)command.c_str();


		//check of command uitgevoerd kan worden, 0 return is goed
		if(!access(commandChar, F_OK))
		{
			//cout << "command:" << commandChar << endl;
			execv(commandChar, argv );
		}
	}

	//geen werkende match gevonden met system variable, problem command zonder path
	//cout << "command:" << argv[0] << endl;
	execv(argv[0], argv );



}

vector<string> Command::getPaths()
{
	string segment;
	stringstream patch(getenv("PATH")); //getenv("PATH")
	vector<string> tokens;


	 for (std::string each; std::getline(patch, segment, ':'); tokens.push_back(segment));

//	 for(int i=0; i < tokens.size(); i++){
//		cout << "__" << tokens[i] << endl;
//	 }

	 return tokens;
}

// vim:ai:aw:ts=4:sw=4:

